// Copyright Leonid Shlyapnikov 2011
// Distributed under the GNU Lesser General Public License http://www.gnu.org/licenses/lgpl.html
//    author: Leonid Shlyapnikov, created on: Apr 1, 2011

#ifndef FIXPARSER_CPP_SRC_MAIN_FIXPARSER_FIELDLIST_H_
#define FIXPARSER_CPP_SRC_MAIN_FIXPARSER_FIELDLIST_H_

#include <boost/utility.hpp>
#include <iterator>
#include <exception>

#include "./Base.h"
#include "./Field.h"

namespace fixparser {

class FieldList;

class FieldListConstIterator {
public:
    typedef ptrdiff_t                   difference_type;
    typedef std::forward_iterator_tag   iterator_category;
    typedef Field                       value_type;
    typedef Field*                      pointer;
    typedef Field&                      reference;


    explicit FieldListConstIterator(Field* field) {
        if (0 == field) {
            BOOST_THROW_EXCEPTION(std::invalid_argument("Argument field is NULL"));
        }
        this->node_ = field;
    }

    virtual ~FieldListConstIterator() {
    }

    Field& operator*() const {
        return *node_;
    }

    Field* operator->() const {
        return node_;
    }

    FieldListConstIterator& operator++() {
        if (node_ == 0) {
            BOOST_THROW_EXCEPTION(std::out_of_range("End of list reached"));
        }
        node_ = node_->next();
        return *this;
    }

    bool operator==(const FieldListConstIterator& that) const {
        return this->node_ == that.node_;
    }

    bool operator!=(const FieldListConstIterator& that) const {
        return this->node_ != that.node_;
    }

    static const FieldListConstIterator& end() {
        static FieldListConstIterator end_;
        return end_;
    }

    // visible for testing
    const Field* current() const {
        return node_;
    }

private:
    FieldListConstIterator(): node_(0) {
    }

    Field* node_;
};


class FieldList: public Base {
public:
    friend class MemoryArea;
    friend class FieldListConstIterator;
    /** For testing only, return the head of the list, head is a dummy node. */
    friend const Field* debug_head_(const FieldList& list);

    typedef FieldListConstIterator  const_iterator;
    typedef FieldListConstIterator  iterator;

    explicit FieldList(MemoryArea* const memoryArea)
        : memoryArea_(memoryArea), size_(0), head_(memoryArea->create<Field>()), back_(head_)
    {}

    virtual ~FieldList() {
    }

    size_t size() const {
        return this->size_;
    }

    bool empty() const {
        return this->size_ == 0;
    }

    /** Returns const Field* to forbid calling setNext() */
    Field* front() const {
        return this->head_->next();
    }

    /** Returns const Field* to forbid calling setNext() */
    Field* back() const {
        return this->back_;
    }

    void push_back(Field* field);

    void clear();

    Field* erase(size_t position); // throws std::out_of_range

    Field& operator[](size_t position) const;

    FieldListConstIterator begin() const {
        return FieldListConstIterator(head_->next());
    }

    FieldListConstIterator end() const {
        return FieldListConstIterator::end();
    }

private:
    std::out_of_range create_out_of_range_exception(size_t position) const;

    MemoryArea* const memoryArea_;
    size_t size_;
    Field* const head_; // always dummy, never counted
    Field* back_;
};


}

#endif  // FIXPARSER_CPP_SRC_MAIN_FIXPARSER_FIELDLIST_H_
